<!DOCTYPE html>
<html lang=en>
<head>
    <!-- so meta -->
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="HandheldFriendly" content="True">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
    <meta name="description" content="OAuth是一个关于授权（authorization）的开放网络标准，在全世界得到广泛应用，目前的版本是2.0版。 本文对OAuth 2.0的设计思路和运行流程，做一个简明通俗的解释，主要参考材料为RFC 6749。 一、应用场景为了理解OAuth的适用场合，让我举一个假设的例子。 有一个”云冲印”的网站，可以将用户储存在Google的照片，冲印出来。用户为了使用该服务，必须让”云冲印”读取自己储">
<meta property="og:type" content="article">
<meta property="og:title" content="理解OAuth2.0">
<meta property="og:url" content="http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/index.html">
<meta property="og:site_name" content="TmoonSite">
<meta property="og:description" content="OAuth是一个关于授权（authorization）的开放网络标准，在全世界得到广泛应用，目前的版本是2.0版。 本文对OAuth 2.0的设计思路和运行流程，做一个简明通俗的解释，主要参考材料为RFC 6749。 一、应用场景为了理解OAuth的适用场合，让我举一个假设的例子。 有一个”云冲印”的网站，可以将用户储存在Google的照片，冲印出来。用户为了使用该服务，必须让”云冲印”读取自己储">
<meta property="og:locale" content="en_US">
<meta property="article:published_time" content="2017-04-07T15:21:09.000Z">
<meta property="article:modified_time" content="2020-01-07T10:48:14.852Z">
<meta property="article:author" content="Tmoonlight">
<meta name="twitter:card" content="summary">
    
    
        
          
              <link rel="shortcut icon" href="/images/favicon.ico">
          
        
        
          
            <link rel="icon" type="image/png" href="/images/logo2.gif" sizes="192x192">
          
        
        
          
            <link rel="apple-touch-icon" sizes="180x180" href="/images/logo2.gif">
          
        
    
    <!-- title -->
    <title>理解OAuth2.0</title>
    <!-- styles -->
    
<link rel="stylesheet" href="/css/style.css">

    <!-- persian styles -->
    
      
<link rel="stylesheet" href="/css/rtl.css">

    
    <!-- rss -->
    
    
<meta name="generator" content="Hexo 4.2.0"></head>

<body class="max-width mx-auto px3 ltr">
    
      <div id="header-post">
  <a id="menu-icon" href="#"><i class="fas fa-bars fa-lg"></i></a>
  <a id="menu-icon-tablet" href="#"><i class="fas fa-bars fa-lg"></i></a>
  <a id="top-icon-tablet" href="#" onclick="$('html, body').animate({ scrollTop: 0 }, 'fast');" style="display:none;"><i class="fas fa-chevron-up fa-lg"></i></a>
  <span id="menu">
    <span id="nav">
      <ul>
         
          <li><a href="/">Home</a></li>
         
          <li><a href="/about/">About</a></li>
         
          <li><a href="/archives/">Writing</a></li>
         
          <li><a href="/projects_url">Projects</a></li>
        
      </ul>
    </span>
    <br/>
    <span id="actions">
      <ul>
        
        <li><a class="icon" href="/2017/04/11/%E4%B8%89%E5%8D%81%E5%88%86%E9%92%9F%E5%AD%A6%E4%BC%9ATypeScript/"><i class="fas fa-chevron-left" aria-hidden="true" onmouseover="$('#i-prev').toggle();" onmouseout="$('#i-prev').toggle();"></i></a></li>
        
        
        <li><a class="icon" href="/2017/04/02/%E5%A6%82%E4%BD%95%E9%85%8D%E7%BD%AEIIS%E5%A4%84%E7%90%86%E5%A4%9A%E5%B9%B6%E5%8F%91%E8%AF%B7%E6%B1%82%E5%8F%8A%E5%AD%98%E5%9C%A8%E7%9A%84%E9%97%AE%E9%A2%98/"><i class="fas fa-chevron-right" aria-hidden="true" onmouseover="$('#i-next').toggle();" onmouseout="$('#i-next').toggle();"></i></a></li>
        
        <li><a class="icon" href="#" onclick="$('html, body').animate({ scrollTop: 0 }, 'fast');"><i class="fas fa-chevron-up" aria-hidden="true" onmouseover="$('#i-top').toggle();" onmouseout="$('#i-top').toggle();"></i></a></li>
        <li><a class="icon" href="#"><i class="fas fa-share-alt" aria-hidden="true" onmouseover="$('#i-share').toggle();" onmouseout="$('#i-share').toggle();" onclick="$('#share').toggle();return false;"></i></a></li>
      </ul>
      <span id="i-prev" class="info" style="display:none;">Previous post</span>
      <span id="i-next" class="info" style="display:none;">Next post</span>
      <span id="i-top" class="info" style="display:none;">Back to top</span>
      <span id="i-share" class="info" style="display:none;">Share post</span>
    </span>
    <br/>
    <div id="share" style="display: none">
      <ul>
  <li><a class="icon" href="http://www.facebook.com/sharer.php?u=http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/" target="_blank" rel="noopener"><i class="fab fa-facebook " aria-hidden="true"></i></a></li>
  <li><a class="icon" href="https://twitter.com/share?url=http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/&text=理解OAuth2.0" target="_blank" rel="noopener"><i class="fab fa-twitter " aria-hidden="true"></i></a></li>
  <li><a class="icon" href="http://www.linkedin.com/shareArticle?url=http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/&title=理解OAuth2.0" target="_blank" rel="noopener"><i class="fab fa-linkedin " aria-hidden="true"></i></a></li>
  <li><a class="icon" href="https://pinterest.com/pin/create/bookmarklet/?url=http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/&is_video=false&description=理解OAuth2.0" target="_blank" rel="noopener"><i class="fab fa-pinterest " aria-hidden="true"></i></a></li>
  <li><a class="icon" href="mailto:?subject=理解OAuth2.0&body=Check out this article: http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/"><i class="fas fa-envelope " aria-hidden="true"></i></a></li>
  <li><a class="icon" href="https://getpocket.com/save?url=http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/&title=理解OAuth2.0" target="_blank" rel="noopener"><i class="fab fa-get-pocket " aria-hidden="true"></i></a></li>
  <li><a class="icon" href="http://reddit.com/submit?url=http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/&title=理解OAuth2.0" target="_blank" rel="noopener"><i class="fab fa-reddit " aria-hidden="true"></i></a></li>
  <li><a class="icon" href="http://www.stumbleupon.com/submit?url=http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/&title=理解OAuth2.0" target="_blank" rel="noopener"><i class="fab fa-stumbleupon " aria-hidden="true"></i></a></li>
  <li><a class="icon" href="http://digg.com/submit?url=http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/&title=理解OAuth2.0" target="_blank" rel="noopener"><i class="fab fa-digg " aria-hidden="true"></i></a></li>
  <li><a class="icon" href="http://www.tumblr.com/share/link?url=http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/&name=理解OAuth2.0&description=" target="_blank" rel="noopener"><i class="fab fa-tumblr " aria-hidden="true"></i></a></li>
  <li><a class="icon" href="https://news.ycombinator.com/submitlink?u=http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/&t=理解OAuth2.0" target="_blank" rel="noopener"><i class="fab fa-hacker-news " aria-hidden="true"></i></a></li>
</ul>

    </div>
    <div id="toc">
      <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#一、应用场景"><span class="toc-number">1.</span> <span class="toc-text">一、应用场景</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#二、名词定义"><span class="toc-number">2.</span> <span class="toc-text">二、名词定义</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#三、OAuth的思路"><span class="toc-number">3.</span> <span class="toc-text">三、OAuth的思路</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#四、运行流程"><span class="toc-number">4.</span> <span class="toc-text">四、运行流程</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#五、客户端的授权模式"><span class="toc-number">5.</span> <span class="toc-text">五、客户端的授权模式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#六、授权码模式"><span class="toc-number">6.</span> <span class="toc-text">六、授权码模式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#七、简化模式"><span class="toc-number">7.</span> <span class="toc-text">七、简化模式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#八、密码模式"><span class="toc-number">8.</span> <span class="toc-text">八、密码模式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#九、客户端模式"><span class="toc-number">9.</span> <span class="toc-text">九、客户端模式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#十、更新令牌"><span class="toc-number">10.</span> <span class="toc-text">十、更新令牌</span></a></li></ol>
    </div>
  </span>
</div>

    
    <div class="content index py4">
        
        <article class="post" itemscope itemtype="http://schema.org/BlogPosting">
  <header>
    
    <h1 class="posttitle" itemprop="name headline">
        理解OAuth2.0
    </h1>



    <div class="meta">
      <span class="author" itemprop="author" itemscope itemtype="http://schema.org/Person">
        <span itemprop="name">TmoonSite</span>
      </span>
      
    <div class="postdate">
      
        <time datetime="2017-04-07T15:21:09.000Z" itemprop="datePublished">2017-04-07</time>
        
      
    </div>


      

      

    </div>
  </header>
  

  <div class="content" itemprop="articleBody">
    <p><a href="http://en.wikipedia.org/wiki/OAuth" target="_blank" rel="noopener">OAuth</a>是一个关于授权（authorization）的开放网络标准，在全世界得到广泛应用，目前的版本是2.0版。</p>
<p>本文对OAuth 2.0的设计思路和运行流程，做一个简明通俗的解释，主要参考材料为<a href="http://www.rfcreader.com/#rfc6749" target="_blank" rel="noopener">RFC 6749</a>。</p>
<h2 id="一、应用场景"><a href="#一、应用场景" class="headerlink" title="一、应用场景"></a>一、应用场景</h2><p>为了理解OAuth的适用场合，让我举一个假设的例子。</p>
<p>有一个”云冲印”的网站，可以将用户储存在Google的照片，冲印出来。用户为了使用该服务，必须让”云冲印”读取自己储存在Google上的照片。</p>
<p>问题是只有得到用户的授权，Google才会同意”云冲印”读取这些照片。那么，”云冲印”怎样获得用户的授权呢？</p>
<p>传统方法是，用户将自己的Google用户名和密码，告诉”云冲印”，后者就可以读取用户的照片了。这样的做法有以下几个严重的缺点。</p>
<blockquote>
<p>（1）”云冲印”为了后续的服务，会保存用户的密码，这样很不安全。</p>
<p>（2）Google不得不部署密码登录，而我们知道，单纯的密码登录并不安全。</p>
<p>（3）”云冲印”拥有了获取用户储存在Google所有资料的权力，用户没法限制”云冲印”获得授权的范围和有效期。</p>
<p>（4）用户只有修改密码，才能收回赋予”云冲印”的权力。但是这样做，会使得其他所有获得用户授权的第三方应用程序全部失效。</p>
<p>（5）只要有一个第三方应用程序被破解，就会导致用户密码泄漏，以及所有被密码保护的数据泄漏。</p>
</blockquote>
<p>OAuth就是为了解决上面这些问题而诞生的。</p>
<h2 id="二、名词定义"><a href="#二、名词定义" class="headerlink" title="二、名词定义"></a>二、名词定义</h2><p>在详细讲解OAuth 2.0之前，需要了解几个专用名词。它们对读懂后面的讲解，尤其是几张图，至关重要。</p>
<blockquote>
<p>（1） Third-party application：第三方应用程序，本文中又称”客户端”（client），即上一节例子中的”云冲印”。</p>
<p>（2）HTTP service：HTTP服务提供商，本文中简称”服务提供商”，即上一节例子中的Google。</p>
<p>（3）Resource Owner：资源所有者，本文中又称”用户”（user）。</p>
<p>（4）User Agent：用户代理，本文中就是指浏览器。</p>
<p>（5）Authorization server：认证服务器，即服务提供商专门用来处理认证的服务器。</p>
<p>（6）Resource server：资源服务器，即服务提供商存放用户生成的资源的服务器。它与认证服务器，可以是同一台服务器，也可以是不同的服务器。</p>
</blockquote>
<p>知道了上面这些名词，就不难理解，OAuth的作用就是让”客户端”安全可控地获取”用户”的授权，与”服务商提供商”进行互动。</p>
<h2 id="三、OAuth的思路"><a href="#三、OAuth的思路" class="headerlink" title="三、OAuth的思路"></a>三、OAuth的思路</h2><p>OAuth在”客户端”与”服务提供商”之间，设置了一个授权层（authorization layer）。”客户端”不能直接登录”服务提供商”，只能登录授权层，以此将用户与客户端区分开来。”客户端”登录授权层所用的令牌（token），与用户的密码不同。用户可以在登录的时候，指定授权层令牌的权限范围和有效期。</p>
<p>“客户端”登录授权层以后，”服务提供商”根据令牌的权限范围和有效期，向”客户端”开放用户储存的资料。</p>
<h2 id="四、运行流程"><a href="#四、运行流程" class="headerlink" title="四、运行流程"></a>四、运行流程</h2><p>OAuth 2.0的运行流程如下图，摘自RFC 6749。</p>
<blockquote>
<p>（A）用户打开客户端以后，客户端要求用户给予授权。</p>
<p>（B）用户同意给予客户端授权。</p>
<p>（C）客户端使用上一步获得的授权，向认证服务器申请令牌。</p>
<p>（D）认证服务器对客户端进行认证以后，确认无误，同意发放令牌。</p>
<p>（E）客户端使用令牌，向资源服务器申请获取资源。</p>
<p>（F）资源服务器确认令牌无误，同意向客户端开放资源。</p>
</blockquote>
<p>不难看出来，上面六个步骤之中，B是关键，即用户怎样才能给于客户端授权。有了这个授权以后，客户端就可以获取令牌，进而凭令牌获取资源。</p>
<p>下面一一讲解客户端获取授权的四种模式。</p>
<h2 id="五、客户端的授权模式"><a href="#五、客户端的授权模式" class="headerlink" title="五、客户端的授权模式"></a>五、客户端的授权模式</h2><p>客户端必须得到用户的授权（authorization grant），才能获得令牌（access token）。OAuth 2.0定义了四种授权方式。</p>
<ul>
<li>授权码模式（authorization code）</li>
<li>简化模式（implicit）</li>
<li>密码模式（resource owner password credentials）</li>
<li>客户端模式（client credentials）</li>
</ul>
<h2 id="六、授权码模式"><a href="#六、授权码模式" class="headerlink" title="六、授权码模式"></a>六、授权码模式</h2><p>授权码模式（authorization code）是功能最完整、流程最严密的授权模式。它的特点就是通过客户端的后台服务器，与”服务提供商”的认证服务器进行互动。</p>
<p>它的步骤如下：</p>
<blockquote>
<p>（A）用户访问客户端，后者将前者导向认证服务器。</p>
<p>（B）用户选择是否给予客户端授权。</p>
<p>（C）假设用户给予授权，认证服务器将用户导向客户端事先指定的”重定向URI”（redirection URI），同时附上一个授权码。</p>
<p>（D）客户端收到授权码，附上早先的”重定向URI”，向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的，对用户不可见。</p>
<p>（E）认证服务器核对了授权码和重定向URI，确认无误后，向客户端发送访问令牌（access token）和更新令牌（refresh token）。</p>
</blockquote>
<p>下面是上面这些步骤所需要的参数。</p>
<p>A步骤中，客户端申请认证的URI，包含以下参数：</p>
<ul>
<li>response_type：表示授权类型，必选项，此处的值固定为”code”</li>
<li>client_id：表示客户端的ID，必选项</li>
<li>redirect_uri：表示重定向URI，可选项</li>
<li>scope：表示申请的权限范围，可选项</li>
<li>state：表示客户端的当前状态，可以指定任意值，认证服务器会原封不动地返回这个值。</li>
</ul>
<p>下面是一个例子。</p>
<blockquote>
<p>GET /authorize?response_type=code&amp;client_id=s6BhdRkqt3&amp;state=xyz</p>
<p>&amp;redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1</p>
<p>Host:<a href="http://server.example.com/" target="_blank" rel="noopener">server.example.com</a></p>
</blockquote>
<p>C步骤中，服务器回应客户端的URI，包含以下参数：</p>
<ul>
<li>code：表示授权码，必选项。该码的有效期应该很短，通常设为10分钟，客户端只能使用该码一次，否则会被授权服务器拒绝。该码与客户端ID和重定向URI，是一一对应关系。</li>
<li>state：如果客户端的请求中包含这个参数，认证服务器的回应也必须一模一样包含这个参数。</li>
</ul>
<p>下面是一个例子。</p>
<blockquote>
<p>HTTP/1.1 302 Found</p>
<p>Location: <a href="https://client.example.com/cb" target="_blank" rel="noopener">https://client.example.com/cb</a>?code=SplxlOBeZQQYbYS6WxSbIA</p>
<p>&amp;state=xyz</p>
</blockquote>
<p>D步骤中，客户端向认证服务器申请令牌的HTTP请求，包含以下参数：</p>
<ul>
<li>grant_type：表示使用的授权模式，必选项，此处的值固定为”authorization_code”。</li>
<li>code：表示上一步获得的授权码，必选项。</li>
<li>redirect_uri：表示重定向URI，必选项，且必须与A步骤中的该参数值保持一致。</li>
<li>client_id：表示客户端ID，必选项。</li>
</ul>
<p>下面是一个例子。</p>
<blockquote>
<p>POST /token HTTP/1.1</p>
<p>Host:<a href="http://server.example.com/" target="_blank" rel="noopener">server.example.com</a></p>
<p>Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW</p>
<p>Content-Type: application/x-www-form-urlencoded</p>
<p>grant_type=authorization_code&amp;code=SplxlOBeZQQYbYS6WxSbIA</p>
<p>&amp;redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb</p>
</blockquote>
<p>E步骤中，认证服务器发送的HTTP回复，包含以下参数：</p>
<ul>
<li>access_token：表示访问令牌，必选项。</li>
<li>token_type：表示令牌类型，该值大小写不敏感，必选项，可以是bearer类型或mac类型。</li>
<li>expires_in：表示过期时间，单位为秒。如果省略该参数，必须其他方式设置过期时间。</li>
<li>refresh_token：表示更新令牌，用来获取下一次的访问令牌，可选项。</li>
<li>scope：表示权限范围，如果与客户端申请的范围一致，此项可省略。</li>
</ul>
<p>下面是一个例子。</p>
<blockquote>
<p>HTTP/1.1 200 OK</p>
<p>Content-Type: application/json;charset=UTF-8</p>
<p>Cache-Control: no-store</p>
<p>Pragma: no-cache</p>
<p>{</p>
<p>“access_token”:”2YotnFZFEjr1zCsicMWpAA”,</p>
<p>“token_type”:”example”,</p>
<p>“expires_in”:3600,</p>
<p>“refresh_token”:”tGzv3JOkF0XG5Qx2TlKWIA”,</p>
<p>“example_parameter”:”example_value”</p>
<p>}</p>
</blockquote>
<p>从上面代码可以看到，相关参数使用JSON格式发送（Content-Type: application/json）。此外，HTTP头信息中明确指定不得缓存。</p>
<h2 id="七、简化模式"><a href="#七、简化模式" class="headerlink" title="七、简化模式"></a>七、简化模式</h2><p>简化模式（implicit grant type）不通过第三方应用程序的服务器，直接在浏览器中向认证服务器申请令牌，跳过了”授权码”这个步骤，因此得名。所有步骤在浏览器中完成，令牌对访问者是可见的，且客户端不需要认证。</p>
<p>它的步骤如下：</p>
<blockquote>
<p>（A）客户端将用户导向认证服务器。</p>
<p>（B）用户决定是否给于客户端授权。</p>
<p>（C）假设用户给予授权，认证服务器将用户导向客户端指定的”重定向URI”，并在URI的Hash部分包含了访问令牌。</p>
<p>（D）浏览器向资源服务器发出请求，其中不包括上一步收到的Hash值。</p>
<p>（E）资源服务器返回一个网页，其中包含的代码可以获取Hash值中的令牌。</p>
<p>（F）浏览器执行上一步获得的脚本，提取出令牌。</p>
<p>（G）浏览器将令牌发给客户端。</p>
</blockquote>
<p>下面是上面这些步骤所需要的参数。</p>
<p>A步骤中，客户端发出的HTTP请求，包含以下参数：</p>
<ul>
<li>response_type：表示授权类型，此处的值固定为”token”，必选项。</li>
<li>client_id：表示客户端的ID，必选项。</li>
<li>redirect_uri：表示重定向的URI，可选项。</li>
<li>scope：表示权限范围，可选项。</li>
<li>state：表示客户端的当前状态，可以指定任意值，认证服务器会原封不动地返回这个值。</li>
</ul>
<p>下面是一个例子。</p>
<blockquote>
<p>GET /authorize?response_type=token&amp;client_id=s6BhdRkqt3&amp;state=xyz</p>
<p>&amp;redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1</p>
<p>Host: <a href="http://server.example.com/" target="_blank" rel="noopener">server.example.com</a></p>
</blockquote>
<p>C步骤中，认证服务器回应客户端的URI，包含以下参数：</p>
<ul>
<li>access_token：表示访问令牌，必选项。</li>
<li>token_type：表示令牌类型，该值大小写不敏感，必选项。</li>
<li>expires_in：表示过期时间，单位为秒。如果省略该参数，必须其他方式设置过期时间。</li>
<li>scope：表示权限范围，如果与客户端申请的范围一致，此项可省略。</li>
<li>state：如果客户端的请求中包含这个参数，认证服务器的回应也必须一模一样包含这个参数。</li>
</ul>
<p>下面是一个例子。</p>
<blockquote>
<p>HTTP/1.1 302 Found</p>
<p>Location: <a href="http://example.com/cb" target="_blank" rel="noopener">http://example.com/cb</a>#access_token=2YotnFZFEjr1zCsicMWpAA</p>
<p>&amp;state=xyz&amp;token_type=example&amp;expires_in=3600</p>
</blockquote>
<p>在上面的例子中，认证服务器用HTTP头信息的Location栏，指定浏览器重定向的网址。注意，在这个网址的Hash部分包含了令牌。</p>
<p>根据上面的D步骤，下一步浏览器会访问Location指定的网址，但是Hash部分不会发送。接下来的E步骤，服务提供商的资源服务器发送过来的代码，会提取出Hash中的令牌。</p>
<h2 id="八、密码模式"><a href="#八、密码模式" class="headerlink" title="八、密码模式"></a>八、密码模式</h2><p>密码模式（Resource Owner Password Credentials Grant）中，用户向客户端提供自己的用户名和密码。客户端使用这些信息，向”服务商提供商”索要授权。</p>
<p>在这种模式中，用户必须把自己的密码给客户端，但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下，比如客户端是操作系统的一部分，或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下，才能考虑使用这种模式。</p>
<p>它的步骤如下：</p>
<blockquote>
<p>（A）用户向客户端提供用户名和密码。</p>
<p>（B）客户端将用户名和密码发给认证服务器，向后者请求令牌。</p>
<p>（C）认证服务器确认无误后，向客户端提供访问令牌。</p>
</blockquote>
<p>B步骤中，客户端发出的HTTP请求，包含以下参数：</p>
<ul>
<li>grant_type：表示授权类型，此处的值固定为”password”，必选项。</li>
<li>username：表示用户名，必选项。</li>
<li>password：表示用户的密码，必选项。</li>
<li>scope：表示权限范围，可选项。</li>
</ul>
<p>下面是一个例子。</p>
<blockquote>
<p>POST /token HTTP/1.1</p>
<p>Host: <a href="http://server.example.com/" target="_blank" rel="noopener">server.example.com</a></p>
<p>Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW</p>
<p>Content-Type: application/x-www-form-urlencoded</p>
<p>grant_type=password&amp;username=johndoe&amp;password=A3ddj3w</p>
</blockquote>
<p>C步骤中，认证服务器向客户端发送访问令牌，下面是一个例子。</p>
<blockquote>
<p>HTTP/1.1 200 OK</p>
<p>Content-Type: application/json;charset=UTF-8</p>
<p>Cache-Control: no-store</p>
<p>Pragma: no-cache</p>
<p>{</p>
<p>“access_token”:”2YotnFZFEjr1zCsicMWpAA”,</p>
<p>“token_type”:”example”,</p>
<p>“expires_in”:3600,</p>
<p>“refresh_token”:”tGzv3JOkF0XG5Qx2TlKWIA”,</p>
<p>“example_parameter”:”example_value”</p>
<p>}</p>
</blockquote>
<p>上面代码中，各个参数的含义参见《授权码模式》一节。</p>
<p>整个过程中，客户端不得保存用户的密码。</p>
<h2 id="九、客户端模式"><a href="#九、客户端模式" class="headerlink" title="九、客户端模式"></a>九、客户端模式</h2><p>客户端模式（Client Credentials Grant）指客户端以自己的名义，而不是以用户的名义，向”服务提供商”进行认证。严格地说，客户端模式并不属于OAuth框架所要解决的问题。在这种模式中，用户直接向客户端注册，客户端以自己的名义要求”服务提供商”提供服务，其实不存在授权问题。</p>
<p>它的步骤如下：</p>
<blockquote>
<p>（A）客户端向认证服务器进行身份认证，并要求一个访问令牌。</p>
<p>（B）认证服务器确认无误后，向客户端提供访问令牌。</p>
</blockquote>
<p>A步骤中，客户端发出的HTTP请求，包含以下参数：</p>
<ul>
<li>granttype：表示授权类型，此处的值固定为”clientcredentials”，必选项。</li>
<li>scope：表示权限范围，可选项。</li>
</ul>
<blockquote>
<p>POST /token HTTP/1.1</p>
<p>Host: <a href="http://server.example.com/" target="_blank" rel="noopener">server.example.com</a></p>
<p>Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW</p>
<p>Content-Type: application/x-www-form-urlencoded</p>
<p>grant_type=client_credentials</p>
</blockquote>
<p>认证服务器必须以某种方式，验证客户端身份。</p>
<p>B步骤中，认证服务器向客户端发送访问令牌，下面是一个例子。</p>
<blockquote>
<p>HTTP/1.1 200 OK</p>
<p>Content-Type: application/json;charset=UTF-8</p>
<p>Cache-Control: no-store</p>
<p>Pragma: no-cache</p>
<p>{</p>
<p>“access_token”:”2YotnFZFEjr1zCsicMWpAA”,</p>
<p>“token_type”:”example”,</p>
<p>“expires_in”:3600,</p>
<p>“example_parameter”:”example_value”</p>
<p>}</p>
</blockquote>
<p>上面代码中，各个参数的含义参见《授权码模式》一节。</p>
<h2 id="十、更新令牌"><a href="#十、更新令牌" class="headerlink" title="十、更新令牌"></a>十、更新令牌</h2><p>如果用户访问的时候，客户端的”访问令牌”已经过期，则需要使用”更新令牌”申请一个新的访问令牌。</p>
<p>客户端发出更新令牌的HTTP请求，包含以下参数：</p>
<ul>
<li>granttype：表示使用的授权模式，此处的值固定为”refreshtoken”，必选项。</li>
<li>refresh_token：表示早前收到的更新令牌，必选项。</li>
<li>scope：表示申请的授权范围，不可以超出上一次申请的范围，如果省略该参数，则表示与上一次一致。</li>
</ul>
<p>下面是一个例子。</p>
<blockquote>
<p>POST /token HTTP/1.1</p>
<p>Host: <a href="http://server.example.com/" target="_blank" rel="noopener">server.example.com</a></p>
<p>Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW</p>
<p>Content-Type: application/x-www-form-urlencoded</p>
<p>grant_type=refresh_token&amp;refresh_token=tGzv3JOkF0XG5Qx2TlKWIA</p>
</blockquote>
<p>（完）</p>

  </div>
</article>



        
          <div id="footer-post-container">
  <div id="footer-post">

    <div id="nav-footer" style="display: none">
      <ul>
         
          <li><a href="/">Home</a></li>
         
          <li><a href="/about/">About</a></li>
         
          <li><a href="/archives/">Writing</a></li>
         
          <li><a href="/projects_url">Projects</a></li>
        
      </ul>
    </div>

    <div id="toc-footer" style="display: none">
      <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#一、应用场景"><span class="toc-number">1.</span> <span class="toc-text">一、应用场景</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#二、名词定义"><span class="toc-number">2.</span> <span class="toc-text">二、名词定义</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#三、OAuth的思路"><span class="toc-number">3.</span> <span class="toc-text">三、OAuth的思路</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#四、运行流程"><span class="toc-number">4.</span> <span class="toc-text">四、运行流程</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#五、客户端的授权模式"><span class="toc-number">5.</span> <span class="toc-text">五、客户端的授权模式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#六、授权码模式"><span class="toc-number">6.</span> <span class="toc-text">六、授权码模式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#七、简化模式"><span class="toc-number">7.</span> <span class="toc-text">七、简化模式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#八、密码模式"><span class="toc-number">8.</span> <span class="toc-text">八、密码模式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#九、客户端模式"><span class="toc-number">9.</span> <span class="toc-text">九、客户端模式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#十、更新令牌"><span class="toc-number">10.</span> <span class="toc-text">十、更新令牌</span></a></li></ol>
    </div>

    <div id="share-footer" style="display: none">
      <ul>
  <li><a class="icon" href="http://www.facebook.com/sharer.php?u=http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/" target="_blank" rel="noopener"><i class="fab fa-facebook fa-lg" aria-hidden="true"></i></a></li>
  <li><a class="icon" href="https://twitter.com/share?url=http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/&text=理解OAuth2.0" target="_blank" rel="noopener"><i class="fab fa-twitter fa-lg" aria-hidden="true"></i></a></li>
  <li><a class="icon" href="http://www.linkedin.com/shareArticle?url=http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/&title=理解OAuth2.0" target="_blank" rel="noopener"><i class="fab fa-linkedin fa-lg" aria-hidden="true"></i></a></li>
  <li><a class="icon" href="https://pinterest.com/pin/create/bookmarklet/?url=http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/&is_video=false&description=理解OAuth2.0" target="_blank" rel="noopener"><i class="fab fa-pinterest fa-lg" aria-hidden="true"></i></a></li>
  <li><a class="icon" href="mailto:?subject=理解OAuth2.0&body=Check out this article: http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/"><i class="fas fa-envelope fa-lg" aria-hidden="true"></i></a></li>
  <li><a class="icon" href="https://getpocket.com/save?url=http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/&title=理解OAuth2.0" target="_blank" rel="noopener"><i class="fab fa-get-pocket fa-lg" aria-hidden="true"></i></a></li>
  <li><a class="icon" href="http://reddit.com/submit?url=http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/&title=理解OAuth2.0" target="_blank" rel="noopener"><i class="fab fa-reddit fa-lg" aria-hidden="true"></i></a></li>
  <li><a class="icon" href="http://www.stumbleupon.com/submit?url=http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/&title=理解OAuth2.0" target="_blank" rel="noopener"><i class="fab fa-stumbleupon fa-lg" aria-hidden="true"></i></a></li>
  <li><a class="icon" href="http://digg.com/submit?url=http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/&title=理解OAuth2.0" target="_blank" rel="noopener"><i class="fab fa-digg fa-lg" aria-hidden="true"></i></a></li>
  <li><a class="icon" href="http://www.tumblr.com/share/link?url=http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/&name=理解OAuth2.0&description=" target="_blank" rel="noopener"><i class="fab fa-tumblr fa-lg" aria-hidden="true"></i></a></li>
  <li><a class="icon" href="https://news.ycombinator.com/submitlink?u=http://yoursite.com/2017/04/07/%E7%90%86%E8%A7%A3OAuth2.0/&t=理解OAuth2.0" target="_blank" rel="noopener"><i class="fab fa-hacker-news fa-lg" aria-hidden="true"></i></a></li>
</ul>

    </div>

    <div id="actions-footer">
        <a id="menu" class="icon" href="#" onclick="$('#nav-footer').toggle();return false;"><i class="fas fa-bars fa-lg" aria-hidden="true"></i> Menu</a>
        <a id="toc" class="icon" href="#" onclick="$('#toc-footer').toggle();return false;"><i class="fas fa-list fa-lg" aria-hidden="true"></i> TOC</a>
        <a id="share" class="icon" href="#" onclick="$('#share-footer').toggle();return false;"><i class="fas fa-share-alt fa-lg" aria-hidden="true"></i> Share</a>
        <a id="top" style="display:none" class="icon" href="#" onclick="$('html, body').animate({ scrollTop: 0 }, 'fast');"><i class="fas fa-chevron-up fa-lg" aria-hidden="true"></i> Top</a>
    </div>

  </div>
</div>

        
        <footer id="footer">
  <div class="footer-left">
    Copyright &copy; 2020 Tmoonlight
  </div>
  <div class="footer-right">
    <nav>
      <ul>
         
          <li><a href="/">Home</a></li>
         
          <li><a href="/about/">About</a></li>
         
          <li><a href="/archives/">Writing</a></li>
         
          <li><a href="/projects_url">Projects</a></li>
        
      </ul>
    </nav>
  </div>
</footer>

    </div>
    <!-- styles -->

<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">


<link rel="stylesheet" href="/lib/justified-gallery/css/justifiedGallery.min.css">


    <!-- jquery -->

<script src="/lib/jquery/jquery.min.js"></script>


<script src="/lib/justified-gallery/js/jquery.justifiedGallery.min.js"></script>

<!-- clipboard -->

  
<script src="/lib/clipboard/clipboard.min.js"></script>

  <script type="text/javascript">
  $(function() {
    // copy-btn HTML
    var btn = "<span class=\"btn-copy tooltipped tooltipped-sw\" aria-label=\"Copy to clipboard!\">";
    btn += '<i class="far fa-clone"></i>';
    btn += '</span>'; 
    // mount it!
    $(".highlight table").before(btn);
    var clip = new ClipboardJS('.btn-copy', {
      text: function(trigger) {
        return Array.from(trigger.nextElementSibling.querySelectorAll('.code')).reduce((str,it)=>str+it.innerText+'\n','')
      }
    });
    clip.on('success', function(e) {
      e.trigger.setAttribute('aria-label', "Copied!");
      e.clearSelection();
    })
  })
  </script>


<script src="/js/main.js"></script>

<!-- search -->

<!-- Google Analytics -->

<!-- Baidu Analytics -->

<!-- Disqus Comments -->


</body>
</html>
